/*
 correspondence2D.js
 Austin Abrams, Washington University in St. Louis
 4/28/2010
 
 A set of scripts to move 2D points and an incident polygon around the canvas.
 
 Requirements:
	- canvas.js
	- canvasPoint.js
	- helperFunctions.js
 */

// some color constants.
const POINT_COLORS = new Array("red", "green", "blue", "yellow");
const SNAPPED_STROKE_COLOR = "white";
const UNSNAPPED_STROKE_COLOR = "black";
const POINT_LINE_WIDTH = 2;

const POLYGON_FILL = "rgba(255, 255, 255, 0.25)";
const POLYGON_STROKE = "black";
const POLYGON_LINE_WIDTH = 2;

const PREVIOUS_STROKE = "rgba(255,255,255,1)";
const PREVIOUS_FILL = "rgba(0,0,0,0.25)";
const PREVIOUS_LINE_WIDTH = 1;

const RENDER_ORIGINAL_IMAGE_URL = (Site.DEBUG) ? 'http://localhost:8080/renderOriginalImage/' : 'http://www.projectlive3d.com/renderOriginalImage/'

function Build2D(url, sceneId) {
	// set the mouse listeners.
	var canvas = document.getElementById('canvasObject');
	this.canvas = canvas;

	// find the canvas offset.
	this.canvasOffset = findPos(canvas);
	this.zoomBox = new ZoomBox();
	
	// TODO: create other points.
	this.polygonSet = new Array();
	this.previousPoints = new Array();
	this.previousPointIndices = new Array();
	this.previousTriangles = new Array();
	
	this.updateSnap();
	this.updateDepthAssist();
	this.updateCenter();
	
	this.buildPoly();

	this.draggedPoint = null;
	this.scroll = true;

	this.url = url;
	this.sceneId = sceneId;
	if ( document.getElementById('firstImageToggle') ) {
		this.toggleFirstImage();
	}
}

Build2D.prototype.saveAndAdd = function() {
	for ( var i = 0; i < this.polygon.vertices; i++ ) {
		this.polygon.points[i].setStyle(PREVIOUS_STROKE, SNAPPED_STROKE_COLOR, UNSNAPPED_STROKE_COLOR, POINT_LINE_WIDTH);
	}

	this.polygonSet[this.polygonSet.length] = this.polygon;
	this.polygonSet[this.polygonSet.length-1].setStyle(PREVIOUS_STROKE, PREVIOUS_FILL, PREVIOUS_LINE_WIDTH);

	if ( document.getElementById('polyName').value == "" ) {
		this.polygonSet[this.polygonSet.length-1].polyName = 'none';
	} else {
		this.polygonSet[this.polygonSet.length-1].polyName = document.getElementById('polyName').value;
	}
	
	this.buildPoly();
}
Build2D.prototype.discardChanges = function() {
	this.polygonSet = new Array();
	this.buildPoly();
}

Build2D.prototype.polygonsToString = function() {
	var d = "";
	for ( var i = 0; i < this.polygonSet.length; i++ ) {
		d += "Polygon " + i + " of " + this.polygonSet.length + "<br />";
		for ( var j = 0; j < this.polygonSet[i].points.length; j++ ) {
			d += "Point " + j + ": (" + this.polygonSet[i].points[j].u + ", " + this.polygonSet[i].points[j].v + ")<br />";
		}
	}
	d += "Current polygon:<br />";
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		d += "Point " + i + ": (" + this.polygon.points[i].u + ", " + this.polygon.points[i].v + ")<br />";
	}
	d += "Done.";
}

Build2D.prototype.toggleFirstImage = function() {
	var checked = document.getElementById('firstImageToggle').checked;
	var me = this;
	if ( checked ) {
		loadImage(RENDER_ORIGINAL_IMAGE_URL + this.sceneId + '.jpg', function(obj){ obj.drawEverything()}, me);
	} else {
		loadImage(this.url, function(obj){ obj.drawEverything()}, me);
	}
}

Build2D.prototype.toggleZoomView = function() {
	this.zoomBox.active = document.getElementById('showzoombox').checked;
}

Build2D.prototype.movedPoints = function() {
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		if ( !this.polygon.points[i].movedPoint ) {
			return false;
		}
	}
	return true;
}

Build2D.prototype.movedAPoint = function() {
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		if ( this.polygon.points[i].movedPoint ) {
			return true;
		}
	}
	return false;
}

// parses the DOM and reads how many sides a polygon should have.
Build2D.prototype.buildPoly = function() {
	this.center = scrollChange("imagecontainer");
	var type = "";
	for ( i = 0; i < document.corrForm.correspondence.length; i++ ) {
		if ( document.corrForm.correspondence[i].checked == true ) {
			type = document.corrForm.correspondence[i].value;
			break;
		}
	}
	if ( type != "" ) {
		var sides = parseInt(type);
		this.polygon = new Polygon2D();
		this.polygon.buildNGon(sides, this.center)
		
		for ( var i = 0; i < sides; i++ ) {
			this.polygon.points[i].setStyle(POINT_COLORS[i], SNAPPED_STROKE_COLOR, UNSNAPPED_STROKE_COLOR, POINT_LINE_WIDTH)
			this.polygon.points[i].index = i;
		}
		this.polygon.setStyle(POLYGON_STROKE, POLYGON_FILL, POLYGON_LINE_WIDTH);
	}

	this.drawEverything();
	this.scroll = true;
}

// Tracks mouse movement and updates point locations.
Build2D.prototype.mouseup = function(ev) {
	if ( this.draggedPoint ) {	
		this.draggedPoint.setDragged(false);
		this.draggedPoint = null;
		this.zoomBox.undraw();
	}

	this.drawEverything();
}

Build2D.prototype.mousedown = function(ev) {
	var mousePoint = mousePos(ev, "imagecontainer", this.canvasOffset.x, this.canvasOffset.y);
	var x = mousePoint.x;
	var y = mousePoint.y;
	
	for ( var i = 0 ; i < this.polygon.points.length; i++ ){
		var point = this.polygon.points[i];
		if ( point.onXY(x,y) ) {
			this.draggedPoint = point;
			this.zoomBox.setPosition(x,y);

			if ( this.zoomBox.active ) {
				this.zoomBox.draw();
			}
		}
	}
}

// Tracks mouse movement and updates point locations.
Build2D.prototype.mousemove = function(ev) {
	var mousePoint = mousePos(ev, "imagecontainer", this.canvasOffset.x, this.canvasOffset.y);
	var x = mousePoint.x;
	var y = mousePoint.y;

	if ( this.draggedPoint ) {
		if ( !this.snapping ) {
			this.draggedPoint.setPosition(x,y);
			_buildMovedPoint();
			this.draggedPoint.setSnapped(false);
		} else {
			this.draggedPoint.snapPoint(x,y, this.previousPoints);
		}

		this.zoomBox.setPosition(x, y);
		this.drawEverything();

		// depth assistance.
		if ( document.getElementById('depthbox') && document.getElementById('depthbox').checked ) {
			this.depthAssistance(x, y, this.draggedPoint.index);
		}
		this.scroll = false;
	}
}


// draws the image and the polygon/point.
Build2D.prototype.drawEverything = function() {
	if ( img.naturalWidth ) {
		drawImage();
	}

	for ( var i in this.previousPoints ) {
		this.previousPoints[i].draw();
	}

	for ( var i = 0; i < this.previousTriangles.length; i++ ) {
		this.previousTriangles[i].draw();
	}
	
	if ( this.polygonSet.length > 0 ) {
		for ( var i = 0; i < this.polygonSet.length; i++ ) { 
			this.polygonSet[i].draw();
		}
	}

	this.polygon.draw();

	if ( this.draggedPoint && this.zoomBox.active ) {
		this.zoomBox.draw();
	} 
}

// update all the (u,v) elements on the form.
Build2D.prototype.dumpToHTML = function() {
	if ( this.movedPoints() ) {
		this.polygonSet[this.polygonSet.length] = this.polygon;
	}
	
	var imageUString = '';
	var imageVString = '';
	var triangleString = '';
	var nameString = '';

	for ( var i = 0; i < this.polygonSet.length; i++ ) {
		for ( var j = 0; j < this.polygonSet[i].vertices; j++ ) {
			imageUString += Math.round(this.polygonSet[i].points[j].u);
			imageVString += Math.round(this.polygonSet[i].points[j].v);

			if ( j < this.polygonSet[i].vertices-1 ) {
				imageUString += ' ';
				imageVString += ' ';
			}
		}

		for ( var j = 0; j < this.polygonSet[i].triangles.length; j++ ) {
			for ( var k = 0; k < 3; k++ ) {
				triangleString += this.polygonSet[i].triangles[j][k];
				if ( k < 2 || j < this.polygonSet[i].triangles.length-1) triangleString += ' ';
			}
		}

		nameString += this.polygonSet[i].polyName;

		if ( i < this.polygonSet.length-1 ) {
			imageUString += ';';
			imageVString += ';';
			triangleString += ';';
			nameString += ';';
		}

	}
	document.getElementById("imageUs").value = imageUString;
	document.getElementById("imageVs").value = imageVString;
	document.getElementById("triangleIndices").value = triangleString;
	document.getElementById("polyNames").value = nameString;
}

Build2D.prototype.updateCenter = function() {
	this.zoomBox.updateEdges();

	if ( this.scroll ) {
		this.center = scrollChange("imagecontainer");
		this.buildPoly();	
	}
}

Build2D.prototype.updateSnap = function() {
	if (document.getElementById('snapbox'))
		this.snapping = document.getElementById('snapbox').checked;
}

Build2D.prototype.updateDepthAssist = function() {
	if (document.getElementById('depthbox'))
		this.depthAssist = document.getElementById('depthbox').checked;
}

Build2D.prototype.addPreviousPoint = function(index, u, v) {
	var point = new Point2D(u,v,false);
	point.setStyle(PREVIOUS_FILL, PREVIOUS_STROKE, PREVIOUS_STROKE, PREVIOUS_LINE_WIDTH)
	this.previousPoints[index] = point;
}

Build2D.prototype.addPreviousTriangle = function(mapping, triangles) {
	var previousMesh = new Polygon2D();
	for ( var i = 0; i < mapping.length; i++ ) {
		previousMesh.addPoint(this.previousPoints[mapping[i]]);
	}
	
	for ( var i = 0; i < triangles.length; i = i + 3 ) {
		previousMesh.addTriangle(triangles[i], triangles[i+1], triangles[i+2]);
	}
	previousMesh.setStyle(PREVIOUS_STROKE, PREVIOUS_FILL, PREVIOUS_LINE_WIDTH)
	this.previousTriangles[this.previousTriangles.length] = previousMesh;
}

// make an estimate of where the 3D point should be, given the (u,v) image
// coordinates.
Build2D.prototype.depthAssistance = function(u,v,pointI) {
	if (calib == undefined) {
		return;
	}
	if (ge == undefined) {
		return;
	}
	if (build3D == undefined) {
		return;
	}
	var point3D = build3D.polygon.points[pointI];
	if (point3D == null || point3D == undefined){

		return;
	}
	ge.getOptions().setFlyToSpeed(ge.SPEED_TELEPORT); 
	
	// find the pitch and heading that moves the camera so that (u,v)
	// is in the center of the virtual camera.
	var ray = calib.uv2xyz(u,v, 50);
	var radius = Math.sqrt(ray.x * ray.x + ray.y * ray.y + ray.z * ray.z)
	var tiltRad = Math.acos(ray.z/radius)
	var headingRad = Math.atan2(ray.y, ray.x)
	var tiltDeg = 180 - tiltRad * 180 / PI;
	var headingDeg = 90 - headingRad * 180 / PI;
	
	// move the camera.
	var cam = ge.getView().copyAsCamera(ge.ALTITUDE_ABSOLUTE);
	cam.setLatitude(calib.camCenter.lat);
	cam.setLongitude(calib.camCenter.lon);
	cam.setAltitude(calib.camCenter.alt);
	cam.setRoll(0);
	cam.setTilt(tiltDeg);
	cam.setHeading(headingDeg);
	
	ge.getView().setAbstractView(cam);
	var geolocation = absoluteHitTestPercent(0.5, 0.5);
	
	if (geolocation != null){
		point3D.setLoc(geolocation.lat, geolocation.lon, geolocation.alt);
		// update the 3D polygon.
		for (var i = 0; i < point3D.parentTriangles.length; i++){
			point3D.parentTriangles[i].updateEdges();
		}
		build3D.polygon.draw();
		point3D.movedPoint = true;
	}
	ge.getOptions().setFlyToSpeed(1); 
}